(async () => {
    
    const ldurls = {
        jq: 'https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js',
        jqui: 'https://cdn.jsdelivr.net/npm/jquery-ui-dist@1.13.0/jquery-ui.min.js',
        jquicss: 'https://cdn.jsdelivr.net/npm/jquery-ui-dist@1.13.0/jquery-ui.min.css',
    };
    
    const ald = (name, attrs) => new Promise((res, rej) => {
        let nd = document.createElement(name);
        Object.assign(nd, attrs);
        nd.async = true;
        nd.onload = res;
        nd.onerror = rej;
        document.head.appendChild(nd);
    });
    
    const asleep = ms => new Promise(resolve => {
        setTimeout(resolve, ms);
    });
    
    if(typeof(jQuery) === 'undefined' || !jQuery) {
        await ald('script', {type: 'text/javascript', src: ldurls.jq});
    }
    
    const $ = jQuery;
    
    if(!$?.ui || $.ui.version != '1.13.0') {
        await ald('link', {rel: 'stylesheet', type: 'text/css', href: ldurls.jquicss});
        await ald('script', {type: 'text/javascript', src: ldurls.jqui});
    }
    
    const glb_style = `
        #speech_main {
            width: 200px;
            height: 300px;
            background: #f0f0f0;
            padding: 0;
        }
        #speech_sctab {
            position: relative;
            overflow: hidden;
        }
        #speech_text {
            position: absolute;
            bottom: 0;
        }
        .speech_talking {
            font-weight: bold;
            color: #0c0c0c;
        }
        .speech_told {
            font-weight: normal;
            color: #808080;
        }
        .speech_untold {
            font-weight: normal;
            color: #101010;
        }
    `;
    $(document.head).append($('<style>').text(glb_style));
    
    const speak = s => new Promise(resolve => {
        let u = new SpeechSynthesisUtterance(s);
        u.onend = resolve;
        speechSynthesis.speak(u);
    });
    
    const new_mwin = async () => {
        let mwin = $('<div>').attr('id', 'speech_main').css({
            position: 'fixed',
            left: 0,
            top: 0,
    }   );
        mwin.draggable().resizable();
        
        let scr_tab = $('<div>').attr('id', 'speech_sctab');
        let txt_area = $('<div>').attr('id', 'speech_text');
        let txt_input = $('<input>').attr('id', 'speech_input');
        
        let mwin_on_resize = () => {
            scr_tab.outerWidth(mwin.width());
            txt_area.outerWidth(mwin.width());
            txt_input.outerWidth(mwin.width());
            scr_tab.outerHeight(mwin.height() - txt_input.outerHeight());
        };
        
        let ti_on_input = e => {
            if (e.keyCode !== 13) return;
            let s = txt_input.val();
            txt_input.val('')
            ta_emit(s);
        };
        
        let ta_idx = 0;
        let ta_emit = s => {
            if(!s) return;
            txt_area.append(
                $('<div>').attr('id', 'speech_txt_' + ta_idx).addClass('speech_untold')
                .data('ta_idx', ta_idx).text(s)
            );
            ta_idx++;
            speech_loop(); //no wait
        };
        
        let speech_lock = false;
        let speech_loop = async () => {
            if(speech_lock) return;
            speech_lock = true;
            //console.log('speak start');
            let nd;
            while((nd = $('.speech_untold').first()).length > 0) {
                //console.log('say', nd.text());
                //await asleep(2000);
                nd.removeClass('speech_untold').addClass('speech_talking');
                await speak(nd.text());
                nd.removeClass('speech_talking').addClass('speech_told');
            }
            //console.log('speak done');
            speech_lock = false;
        };
        
        mwin.on('resize', mwin_on_resize);
        txt_input.on('keypress', ti_on_input);
        
        mwin.append(scr_tab.append(txt_area)).append(txt_input);
        $(document.body).append(mwin);
        mwin_on_resize();
    };
    
    let mwin = $('#speech_main');
    if(mwin.length === 0) {
        await new_mwin();
    }
    
})();